using UnityEngine;

[RequireComponent(typeof(VehicleParent))]
public class VehicleDamage : MonoBehaviour
{
	private Transform tr;

	private Rigidbody rb;

	private VehicleParent vp;

	[Range(0f, 1f)]
	public float strength = 1f;

	public float damageFactor = 1f;

	public float maxCollisionMagnitude = 100f;

	[Tooltip("Maximum collision points to use when deforming, has large effect on performance")]
	public int maxCollisionPoints = 2;

	[Tooltip("Collisions underneath this local y-position will be ignored")]
	public float collisionIgnoreHeight;

	[Tooltip("If true, grounded wheels will not be damaged, but can still be displaced")]
	public bool ignoreGroundedWheels;

	[Tooltip("Minimum time in seconds between collisions")]
	public float collisionTimeGap = 0.1f;

	private float hitTime;

	[Tooltip("Whether the edges of adjacent deforming parts should match")]
	public bool seamlessDeform;

	[Tooltip("Add some perlin noise to deformation")]
	public bool usePerlinNoise = true;

	[Tooltip("Recalculate normals of deformed meshes")]
	public bool calculateNormals = true;

	[Tooltip("Parts that are damaged")]
	public Transform[] damageParts;

	[Tooltip("Meshes that are deformed")]
	public MeshFilter[] deformMeshes;

	private bool[] damagedMeshes;

	private Mesh[] tempMeshes;

	private meshVerts[] meshVertices;

	[Tooltip("Mesh colliders that are deformed (Poor performance, must be convex)")]
	public MeshCollider[] deformColliders;

	private bool[] damagedCols;

	private Mesh[] tempCols;

	private meshVerts[] colVertices;

	[Tooltip("Parts that are displaced")]
	public Transform[] displaceParts;

	private Vector3[] initialPartPositions;

	private void Start()
	{
		tr = base.transform;
		rb = GetComponent<Rigidbody>();
		vp = GetComponent<VehicleParent>();
		vp.playCrashSounds = false;
		vp.playCrashSparks = false;
		tempMeshes = new Mesh[deformMeshes.Length];
		damagedMeshes = new bool[deformMeshes.Length];
		meshVertices = new meshVerts[deformMeshes.Length];
		for (int i = 0; i < deformMeshes.Length; i++)
		{
			tempMeshes[i] = deformMeshes[i].mesh;
			meshVertices[i] = new meshVerts();
			meshVertices[i].verts = deformMeshes[i].mesh.vertices;
			meshVertices[i].initialVerts = deformMeshes[i].mesh.vertices;
			damagedMeshes[i] = false;
		}
		BCWDebug.LogError("VehicleDamage");
		tempCols = new Mesh[deformColliders.Length];
		damagedCols = new bool[deformColliders.Length];
		colVertices = new meshVerts[deformColliders.Length];
		for (int j = 0; j < deformColliders.Length; j++)
		{
			tempCols[j] = Object.Instantiate(deformColliders[j].sharedMesh);
			colVertices[j] = new meshVerts();
			colVertices[j].verts = deformColliders[j].sharedMesh.vertices;
			colVertices[j].initialVerts = deformColliders[j].sharedMesh.vertices;
			damagedCols[j] = false;
		}
		initialPartPositions = new Vector3[displaceParts.Length];
		for (int k = 0; k < displaceParts.Length; k++)
		{
			initialPartPositions[k] = displaceParts[k].localPosition;
		}
	}

	private void FixedUpdate()
	{
		hitTime = Mathf.Max(0f, hitTime - Time.fixedDeltaTime);
		damageFactor = Mathf.Max(0f, damageFactor);
	}

	private void OnCollisionEnter(Collision col)
	{
		if (hitTime != 0f || !(col.relativeVelocity.sqrMagnitude * damageFactor > 1f) || !(strength < 1f))
		{
			return;
		}
		float num = Mathf.Min(col.relativeVelocity.magnitude, maxCollisionMagnitude) * (1f - strength) * damageFactor;
		float num2 = Mathf.Pow(Mathf.Sqrt(num) * 0.5f, 1.5f);
		Vector3 vector = Vector3.ClampMagnitude(col.relativeVelocity, maxCollisionMagnitude);
		Vector3 normalized = col.relativeVelocity.normalized;
		float num3 = 1f;
		Transform transform = null;
		int num4 = 0;
		bool flag = false;
		bool flag2 = false;
		hitTime = collisionTimeGap;
		ContactPoint[] contacts = col.contacts;
		for (int i = 0; i < contacts.Length; i++)
		{
			ContactPoint contactPoint = contacts[i];
			if (tr.InverseTransformPoint(contactPoint.point).y > collisionIgnoreHeight && (int)GlobalControl.damageMaskStatic == ((int)GlobalControl.damageMaskStatic | (1 << contactPoint.otherCollider.gameObject.layer)))
			{
				num4++;
				if ((bool)contactPoint.otherCollider.attachedRigidbody)
				{
					num3 = Mathf.Clamp01(contactPoint.otherCollider.attachedRigidbody.mass / rb.mass);
				}
				if ((bool)vp.crashSnd && vp.crashClips.Length > 0 && !flag)
				{
					vp.crashSnd.PlayOneShot(vp.crashClips[Mathf.RoundToInt(Random.Range(0, vp.crashClips.Length - 1))], Mathf.Clamp01(col.relativeVelocity.magnitude * 0.1f));
					flag = true;
				}
				if ((bool)vp.sparks && !flag2)
				{
					vp.sparks.transform.position = contactPoint.point;
					vp.sparks.transform.rotation = Quaternion.LookRotation(normalized, contactPoint.normal);
					vp.sparks.Play();
					flag2 = true;
				}
				float num5 = Mathf.Clamp01(Vector3.Dot(contactPoint.normal, normalized)) * (Vector3.Dot((tr.position - contactPoint.point).normalized, normalized) + 1f) * 0.5f;
				for (int j = 0; j < damageParts.Length; j++)
				{
					Transform transform2 = damageParts[j];
					float num6 = num * num5 * num3 * Mathf.Min(num2 * 0.01f, num2 * 0.001f / Mathf.Pow(Vector3.Distance(transform2.position, contactPoint.point), num2));
					Motor component = transform2.GetComponent<Motor>();
					if ((bool)component)
					{
						component.health -= num6 * (1f - component.strength);
					}
					Transmission component2 = transform2.GetComponent<Transmission>();
					if ((bool)component2)
					{
						component2.health -= num6 * (1f - component2.strength);
					}
				}
				for (int k = 0; k < deformMeshes.Length; k++)
				{
					MeshFilter meshFilter = deformMeshes[k];
					Vector3 b = meshFilter.transform.InverseTransformPoint(contactPoint.point);
					Vector3 vector2 = meshFilter.transform.InverseTransformDirection(vector);
					Vector3 vector3 = Vector3.ClampMagnitude(vector2, num2);
					ShatterPart component3 = meshFilter.GetComponent<ShatterPart>();
					if ((bool)component3)
					{
						transform = component3.seamKeeper;
						if (Vector3.Distance(meshFilter.transform.position, contactPoint.point) < num * num5 * 0.1f * num3 && num * num5 * num3 > component3.breakForce)
						{
							component3.Shatter();
						}
					}
					if (!(vector2.sqrMagnitude > 0f) || !(strength < 1f))
					{
						continue;
					}
					for (int l = 0; l < meshVertices[k].verts.Length; l++)
					{
						float f = Vector3.Distance(meshVertices[k].verts[l], b);
						float num7 = num2 * 0.001f / Mathf.Pow(f, num2);
						if (num7 > 0.001f)
						{
							damagedMeshes[k] = true;
							if (transform == null || seamlessDeform)
							{
								Vector3 vector4 = ((!seamlessDeform) ? Vector3.Project(normalized, meshVertices[k].verts[l]) : Vector3.zero);
								meshVertices[k].verts[l] += (vector3 - vector4 * ((!usePerlinNoise) ? 1f : (1f + Mathf.PerlinNoise(meshVertices[k].verts[l].x * 100f, meshVertices[k].verts[l].y * 100f)))) * num5 * Mathf.Min(num2 * 0.01f, num7) * num3;
							}
							else
							{
								Vector3 onNormal = transform.InverseTransformPoint(meshFilter.transform.TransformPoint(meshVertices[k].verts[l]));
								meshVertices[k].verts[l] += (vector3 - Vector3.Project(normalized, onNormal) * ((!usePerlinNoise) ? 1f : (1f + Mathf.PerlinNoise(onNormal.x * 100f, onNormal.y * 100f)))) * num5 * Mathf.Min(num2 * 0.01f, num7) * num3;
							}
						}
					}
				}
				transform = null;
				for (int m = 0; m < deformColliders.Length; m++)
				{
					Vector3 b = deformColliders[m].transform.InverseTransformPoint(contactPoint.point);
					Vector3 vector2 = deformColliders[m].transform.InverseTransformDirection(vector);
					Vector3 vector3 = Vector3.ClampMagnitude(vector2, num2);
					if (!(vector2.sqrMagnitude > 0f) || !(strength < 1f))
					{
						continue;
					}
					for (int n = 0; n < colVertices[m].verts.Length; n++)
					{
						float f = Vector3.Distance(colVertices[m].verts[n], b);
						float num7 = num2 * 0.001f / Mathf.Pow(f, num2);
						if (num7 > 0.001f)
						{
							damagedCols[m] = true;
							colVertices[m].verts[n] += vector3 * num5 * Mathf.Min(num2 * 0.01f, num7) * num3;
						}
					}
				}
				for (int num8 = 0; num8 < displaceParts.Length; num8++)
				{
					Transform transform3 = displaceParts[num8];
					Vector3 vector2 = vector;
					Vector3 vector3 = Vector3.ClampMagnitude(vector2, num2);
					if (!(vector2.sqrMagnitude > 0f) || !(strength < 1f))
					{
						continue;
					}
					float f = Vector3.Distance(transform3.position, contactPoint.point);
					float num7 = num2 * 0.001f / Mathf.Pow(f, num2);
					if (!(num7 > 0.001f))
					{
						continue;
					}
					transform3.position += vector3 * num5 * Mathf.Min(num2 * 0.01f, num7) * num3;
					if ((bool)transform3.GetComponent<DetachablePart>())
					{
						DetachablePart component4 = transform3.GetComponent<DetachablePart>();
						if (num * num5 * num3 > component4.looseForce && component4.looseForce >= 0f)
						{
							component4.initialPos = transform3.localPosition;
							component4.Detach(true);
						}
						else if (num * num5 * num3 > component4.breakForce)
						{
							component4.Detach(false);
						}
					}
					else if ((bool)transform3.parent.GetComponent<DetachablePart>())
					{
						DetachablePart component4 = transform3.parent.GetComponent<DetachablePart>();
						if (!component4.detached)
						{
							if (num * num5 * num3 > component4.looseForce && component4.looseForce >= 0f)
							{
								component4.initialPos = transform3.parent.localPosition;
								component4.Detach(true);
							}
							else if (num * num5 * num3 > component4.breakForce)
							{
								component4.Detach(false);
							}
						}
						else if ((bool)component4.hinge)
						{
							component4.displacedAnchor += transform3.parent.InverseTransformDirection(vector3 * num5 * Mathf.Min(num2 * 0.01f, num7) * num3);
						}
					}
					Suspension component5 = transform3.GetComponent<Suspension>();
					if ((bool)component5 && ((!component5.wheel.grounded && ignoreGroundedWheels) || !ignoreGroundedWheels))
					{
						transform3.RotateAround(component5.tr.TransformPoint(component5.damagePivot), Vector3.ProjectOnPlane(contactPoint.point - transform3.position, -vector2.normalized), num2 * num5 * num7 * 20f * num3);
						component5.wheel.damage += num2 * num5 * num7 * 10f * num3;
						if (num2 * num5 * num7 * 10f * num3 > component5.jamForce)
						{
							component5.jammed = true;
						}
						if (num2 * num5 * num7 * 10f * num3 > component5.wheel.detachForce)
						{
							component5.wheel.Detach();
						}
						foreach (SuspensionPart movingPart in component5.movingParts)
						{
							if ((bool)movingPart.connectObj && !movingPart.isHub && !movingPart.solidAxle && !movingPart.connectObj.GetComponent<SuspensionPart>())
							{
								movingPart.connectPoint += movingPart.connectObj.InverseTransformDirection(vector3 * num5 * Mathf.Min(num2 * 0.01f, num7) * num3);
							}
						}
					}
					HoverWheel component6 = transform3.GetComponent<HoverWheel>();
					if ((bool)component6 && ((!component6.grounded && ignoreGroundedWheels) || !ignoreGroundedWheels) && num2 * num5 * num7 * 10f * num3 > component6.detachForce)
					{
						component6.Detach();
					}
				}
			}
			if (num4 >= maxCollisionPoints)
			{
				break;
			}
		}
		for (int num9 = 0; num9 < deformMeshes.Length; num9++)
		{
			if (damagedMeshes[num9])
			{
				tempMeshes[num9].vertices = meshVertices[num9].verts;
				if (calculateNormals)
				{
					tempMeshes[num9].RecalculateNormals();
				}
				tempMeshes[num9].RecalculateBounds();
			}
			damagedMeshes[num9] = false;
		}
		for (int num10 = 0; num10 < deformColliders.Length; num10++)
		{
			if (damagedCols[num10])
			{
				tempCols[num10].vertices = colVertices[num10].verts;
				deformColliders[num10].sharedMesh = null;
				deformColliders[num10].sharedMesh = tempCols[num10];
			}
			damagedCols[num10] = false;
		}
	}

	public void Repair()
	{
		for (int i = 0; i < damageParts.Length; i++)
		{
			if ((bool)damageParts[i].GetComponent<Motor>())
			{
				damageParts[i].GetComponent<Motor>().health = 1f;
			}
			if ((bool)damageParts[i].GetComponent<Transmission>())
			{
				damageParts[i].GetComponent<Transmission>().health = 1f;
			}
		}
		for (int j = 0; j < deformMeshes.Length; j++)
		{
			for (int k = 0; k < meshVertices[j].verts.Length; k++)
			{
				meshVertices[j].verts[k] = meshVertices[j].initialVerts[k];
			}
			tempMeshes[j].vertices = meshVertices[j].verts;
			tempMeshes[j].RecalculateNormals();
			tempMeshes[j].RecalculateBounds();
			ShatterPart component = deformMeshes[j].GetComponent<ShatterPart>();
			if ((bool)component)
			{
				component.shattered = false;
				if ((bool)component.brokenMaterial)
				{
					component.rend.sharedMaterial = component.initialMat;
				}
				else
				{
					component.rend.enabled = true;
				}
			}
		}
		for (int l = 0; l < deformColliders.Length; l++)
		{
			for (int m = 0; m < colVertices[l].verts.Length; m++)
			{
				colVertices[l].verts[m] = colVertices[l].initialVerts[m];
			}
			tempCols[l].vertices = colVertices[l].verts;
			deformColliders[l].sharedMesh = null;
			deformColliders[l].sharedMesh = tempCols[l];
		}
		for (int n = 0; n < displaceParts.Length; n++)
		{
			Transform transform = displaceParts[n];
			transform.localPosition = initialPartPositions[n];
			if ((bool)transform.GetComponent<DetachablePart>())
			{
				transform.GetComponent<DetachablePart>().Reattach();
			}
			else if ((bool)transform.parent.GetComponent<DetachablePart>())
			{
				transform.parent.GetComponent<DetachablePart>().Reattach();
			}
			Suspension component2 = transform.GetComponent<Suspension>();
			if (!component2)
			{
				continue;
			}
			transform.localRotation = component2.initialRotation;
			component2.jammed = false;
			foreach (SuspensionPart movingPart in component2.movingParts)
			{
				if ((bool)movingPart.connectObj && !movingPart.isHub && !movingPart.solidAxle && !movingPart.connectObj.GetComponent<SuspensionPart>())
				{
					movingPart.connectPoint = movingPart.initialConnectPoint;
				}
			}
		}
		Wheel[] wheels = vp.wheels;
		foreach (Wheel wheel in wheels)
		{
			wheel.Reattach();
			wheel.FixTire();
			wheel.damage = 0f;
		}
		HoverWheel[] hoverWheels = vp.hoverWheels;
		foreach (HoverWheel hoverWheel in hoverWheels)
		{
			hoverWheel.Reattach();
		}
	}

	private void OnDrawGizmosSelected()
	{
		Vector3 from = base.transform.TransformPoint(Vector3.up * collisionIgnoreHeight);
		Gizmos.color = Color.red;
		Gizmos.DrawRay(from, Vector3.forward);
		Gizmos.DrawRay(from, Vector3.back);
		Gizmos.DrawRay(from, Vector3.right);
		Gizmos.DrawRay(from, Vector3.left);
	}

	private void OnDestroy()
	{
		Transform[] array = displaceParts;
		foreach (Transform transform in array)
		{
			if ((bool)transform)
			{
				if ((bool)transform.GetComponent<DetachablePart>() && transform.parent == null)
				{
					Object.Destroy(transform.gameObject);
				}
				else if ((bool)transform.parent.GetComponent<DetachablePart>() && transform.parent.parent == null)
				{
					Object.Destroy(transform.parent.gameObject);
				}
			}
		}
	}
}
